/**
 * @Author: Jackey 327156719@qq.com
 * @Date: 2024-11-13 15:43:37
 * @LastEditors: Jackey 327156719@qq.com
 * @LastEditTime: 2024-12-03 17:28:32
 * @FilePath: src/main/java/org/springblade/modules/admin/controller/AiChatController.java
 * @Description: 这是默认设置, 可以在设置》工具》File Description中进行配置
 */
package org.springblade.modules.admin.controller;

import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.entity.ContentType;
import org.springblade.core.secure.utils.AuthUtil;
import org.springblade.core.tool.api.R;
import org.springblade.modules.admin.dto.ChatRequest;
import org.springblade.modules.admin.dto.ConversationRenameRequest;
import org.springblade.modules.admin.dto.FeedbackRequest;
import org.springblade.modules.admin.dto.TextToAudioRequest;
import org.springblade.modules.admin.entity.FeedbackReasons;
import org.springblade.modules.admin.service.FeedbackReasonsService;
import org.springblade.modules.admin.vo.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.http.*;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.HttpServerErrorException;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import org.springframework.web.util.UriComponentsBuilder;

import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotBlank;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;

/**
 * @author Jackey
 * @date 2024年11月13日 15:43
 */
@Slf4j
@RestController
@RequestMapping("/aiChat")
public class AiChatController {

	@Value("${dify.api.url}")
	private String difyApiUrl;

	@Value("${dify.api.key}")
	private String apiKey;

	@Autowired
	private RestTemplate restTemplate;

	@Autowired
	private ObjectMapper objectMapper;

	@Autowired
	private FeedbackReasonsService reasonsService;


	/**
	 * 发送对话消息
	 *
	 * @param chatRequest 聊天请求
	 * @return 聊天响应
	 */
	@PostMapping("/chat")
	public SseEmitter sendChatMessage(@RequestBody ChatRequest chatRequest) {
		// 创建 SseEmitter 实例,设置超时时间
		SseEmitter emitter = new SseEmitter(60000L);

		// 异步处理

		try {
			HttpHeaders headers = new HttpHeaders();
			headers.setBearerAuth(apiKey);
			headers.setContentType(MediaType.APPLICATION_JSON);

			// 构建请求体
			Map<String, Object> requestBody = new HashMap<>();
			requestBody.put("inputs", chatRequest.getInputs());
			requestBody.put("query", chatRequest.getQuery());
			// 设置为streaming模式
			requestBody.put("response_mode", "streaming");
			requestBody.put("conversation_id", chatRequest.getConversationId());
			requestBody.put("user", AuthUtil.getUserId().toString());
			requestBody.put("files", chatRequest.getFiles());

			HttpEntity<Map<String, Object>> requestEntity = new HttpEntity<>(requestBody, headers);

			// 使用RestTemplate进行流式请求
			restTemplate.execute(
				difyApiUrl + "/v1/chat-messages",
				HttpMethod.POST,
				request -> {
					request.getHeaders().putAll(requestEntity.getHeaders());
					request.getBody().write(objectMapper.writeValueAsBytes(requestEntity.getBody()));
				},
				response -> {
					try (BufferedReader reader = new BufferedReader(
						new InputStreamReader(response.getBody()))) {
						String line;
						while ((line = reader.readLine()) != null) {
							if (line.startsWith("data: ")) {
								String jsonData = line.substring(6);
								// 解析事件数据
								ChunkResponse chunk = objectMapper.readValue(
									jsonData, ChunkResponse.class);

								// 发送SSE事件
								emitter.send(chunk);

								// 如果是结束事件，完成发送
								if ("message_end".equals(chunk.getEvent())) {
									emitter.complete();
									break;
								}
							}
						}
					} catch (Exception e) {
						emitter.completeWithError(e);
					}
					return null;
				}
			);
		} catch (Exception e) {
			emitter.completeWithError(e);
		}


		return emitter;
	}

	/**
	 * 停止对话消息
	 *
	 * @param taskId
	 * @return
	 */
	@PostMapping("chat-messages/{taskId}/stop")
	public R<FeedbackResponse> stopChatMessage(@PathVariable("taskId") String taskId) {
		HttpHeaders headers = new HttpHeaders();
		headers.setBearerAuth(apiKey);
		headers.setContentType(MediaType.APPLICATION_JSON);

		// 构建请求体
		Map<String, Object> requestBody = new HashMap<>();
		requestBody.put("user", AuthUtil.getUserId().toString());

		HttpEntity<?> requestEntity = new HttpEntity<>(requestBody, headers);

		ResponseEntity<FeedbackResponse> exchange = restTemplate.exchange(
			difyApiUrl + "/v1/chat-messages/" + taskId + "/stop",
			HttpMethod.POST,
			requestEntity,
			FeedbackResponse.class
		);

		return R.data(exchange.getBody());
	}

	/**
	 * 消息反馈（点赞）:点赞 like, 点踩 dislike, 撤销点赞 null
	 *
	 * @param messageId
	 * @param feedbackRequest
	 * @return
	 */
	@PostMapping("/messages/{messageId}/feedbacks")
	public R<FeedbackResponse> sendMessageFeedback(@PathVariable("messageId") @NotBlank String messageId, @RequestBody FeedbackRequest feedbackRequest) {
		feedbackRequest.setUser(AuthUtil.getUserId().toString());

		FeedbackResponse feedbackResponse = reasonsService.postFeedbackReasons(feedbackRequest, messageId);

		if (feedbackRequest.getRating().equals("dislike")) {
			FeedbackReasons reasons = new FeedbackReasons();
			reasons.setReasonType(feedbackRequest.getReasonType());
			reasons.setReasonName(feedbackRequest.getReasonContent());
			reasonsService.save(reasons);
		}

		return R.data(feedbackResponse);
	}


	/**
	 * 获取下一轮建议问题列表
	 *
	 * @param messageId
	 * @return
	 */
	@GetMapping("/messages/{messageId}/suggested")
	public R<SuggestedQuestionsResponse> getSuggestedQuestions(@PathVariable("messageId") @NotBlank String messageId) {
		// 构建请求头
		HttpHeaders headers = new HttpHeaders();
		headers.setBearerAuth(apiKey);
		headers.setContentType(MediaType.APPLICATION_JSON);

		// 构建请求参数
		UriComponentsBuilder builder = UriComponentsBuilder
			.fromHttpUrl(difyApiUrl + "/v1/messages/" + messageId + "/suggested")
			.queryParam("user", AuthUtil.getUserId().toString());

		HttpEntity<?> requestEntity = new HttpEntity<>(headers);

		ResponseEntity<SuggestedQuestionsResponse> exchange = restTemplate.exchange(
			builder.toUriString(),
			HttpMethod.GET,
			requestEntity,
			SuggestedQuestionsResponse.class
		);

		return R.data(exchange.getBody());
	}

	/**
	 * 获取会话历史消息
	 *
	 * @param conversationId
	 * @param limit
	 * @return
	 */
	@GetMapping("/messages")
	public R<MessageHistoryResponse> getMessageHistory(
		@RequestParam(value = "conversation_id", required = false) String conversationId,
		@RequestParam(value = "limit", defaultValue = "20") @Min(1) @Max(100) Integer limit) {
		// 构建请求头
		HttpHeaders headers = new HttpHeaders();
		headers.setBearerAuth(apiKey);
		headers.setContentType(MediaType.APPLICATION_JSON);

		// 构建URL参数
		UriComponentsBuilder builder = UriComponentsBuilder
			.fromHttpUrl(difyApiUrl + "/v1/messages")
			.queryParam("user", AuthUtil.getUserId().toString())
			.queryParam("limit", limit);

		if (StringUtils.hasText(conversationId)) {
			builder.queryParam("conversation_id", conversationId);
		}

		HttpEntity<?> requestEntity = new HttpEntity<>(headers);

		ResponseEntity<MessageHistoryResponse> exchange = restTemplate.exchange(
			builder.toUriString(),
			HttpMethod.GET,
			requestEntity,
			MessageHistoryResponse.class
		);

		return R.data(exchange.getBody());
	}

	/**
	 * 获取会话列表
	 *
	 * @param limit
	 * @return
	 */
	@GetMapping("/conversations")
	public R<ConversationListResponse> getConversations(
		@RequestParam(value = "limit", defaultValue = "20") @Min(1) @Max(100) Integer limit) {

		// 构建请求头
		HttpHeaders headers = new HttpHeaders();
		headers.setBearerAuth(apiKey);
		headers.setContentType(MediaType.APPLICATION_JSON);

		// 构建URL参数
		UriComponentsBuilder builder = UriComponentsBuilder
			.fromHttpUrl(difyApiUrl + "/v1/conversations")
			.queryParam("user", AuthUtil.getUserId().toString())
			.queryParam("limit", limit);


		HttpEntity<?> requestEntity = new HttpEntity<>(headers);

		ResponseEntity<ConversationListResponse> exchange = restTemplate.exchange(
			builder.toUriString(),
			HttpMethod.GET,
			requestEntity,
			ConversationListResponse.class
		);

		return R.data(exchange.getBody());
	}

	/**
	 * 删除会话
	 *
	 * @param conversationId
	 * @return
	 */
	@DeleteMapping("/conversations/{conversationId}")
	public R<FeedbackResponse> deleteConversation(@PathVariable String conversationId) {
		HttpHeaders headers = new HttpHeaders();
		headers.setBearerAuth(apiKey);
		headers.setContentType(MediaType.APPLICATION_JSON);

		// 构建请求体
		Map<String, Object> requestBody = new HashMap<>();
		requestBody.put("user", AuthUtil.getUserId().toString());

		HttpEntity<?> requestEntity = new HttpEntity<>(requestBody, headers);

		ResponseEntity<FeedbackResponse> exchange = restTemplate.exchange(
			difyApiUrl + "/v1/conversations/" + conversationId,
			HttpMethod.DELETE,
			requestEntity,
			FeedbackResponse.class
		);

		return R.data(exchange.getBody());
	}

	/**
	 * 会话重命名
	 *
	 * @param conversationId
	 * @param request
	 * @return
	 */
	@PostMapping("/conversations/{conversationId}/name")
	public R<ConversationRenameResponse> renameConversation(
		@PathVariable @NotBlank String conversationId,
		@RequestBody @Valid ConversationRenameRequest request) {


		// 构建请求头
		HttpHeaders headers = new HttpHeaders();
		headers.setBearerAuth(apiKey);
		headers.setContentType(MediaType.APPLICATION_JSON);

		// 构建请求体
		Map<String, Object> requestBody = new HashMap<>();
		requestBody.put("user", AuthUtil.getUserId().toString());
		requestBody.put("name", request.getName());

		HttpEntity<?> requestEntity =
			new HttpEntity<>(requestBody, headers);

		ResponseEntity<ConversationRenameResponse> response = restTemplate.exchange(
			difyApiUrl + "/v1/conversations/" + conversationId + "/name",
			HttpMethod.POST,
			requestEntity,
			ConversationRenameResponse.class
		);

		return R.data(response.getBody());

	}

	/**
	 * 语音转文本
	 *
	 * @param file
	 * @return
	 */
	@PostMapping("/audio-to-text")
	public R<AudioToTextResponse> audioToText(
		@RequestParam("file") MultipartFile file,
		@RequestParam(value = "user", required = false) String user) {
		try {
			// 添加调试日志
			log.debug("Received file: name={}, contentType={}, size={}",
				file.getOriginalFilename(),
				file.getContentType(),
				file.getSize());

			// 验证文件
			validateAudioFile(file);

			// 创建请求头
			HttpHeaders headers = new HttpHeaders();
			headers.setBearerAuth(apiKey);
			headers.setContentType(MediaType.MULTIPART_FORM_DATA);

			// 创建MultipartBody
			MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();

			// 添加文件，使用ContentType来确保正确的媒体类型
			ContentType contentType = getAudioContentType(file);
			ByteArrayResource fileResource = new ByteArrayResource(file.getBytes()) {
				@Override
				public String getFilename() {
					return file.getOriginalFilename();
				}

				@Override
				public String getDescription() {
					return contentType.getMimeType();
				}
			};

			HttpHeaders fileHeaders = new HttpHeaders();
			fileHeaders.setContentType(MediaType.parseMediaType(contentType.getMimeType()));
			HttpEntity<ByteArrayResource> fileEntity = new HttpEntity<>(fileResource, fileHeaders);

			body.add("file", fileEntity);

			body.add("user", AuthUtil.getUserId().toString());

			HttpEntity<MultiValueMap<String, Object>> requestEntity =
				new HttpEntity<>(body, headers);

			// 添加请求日志
			log.debug("Sending request to: {}", difyApiUrl + "/v1/audio-to-text");

			ResponseEntity<AudioToTextResponse> response = restTemplate.exchange(
				difyApiUrl + "/v1/audio-to-text",
				HttpMethod.POST,
				requestEntity,
				AudioToTextResponse.class
			);

			if (response.getBody() != null) {
				return R.data(response.getBody());
			} else {
				return R.fail("No text generated from audio");
			}

		} catch (HttpClientErrorException | HttpServerErrorException e) {
			log.error("HTTP error in audio-to-text conversion: {}", e.getResponseBodyAsString());
			return R.fail(e.getStatusCode().value(), e.getResponseBodyAsString());
		} catch (Exception e) {
			log.error("Error in audio-to-text conversion", e);
			return R.fail("Error converting audio to text: " + e.getMessage());
		}
	}


	/**
	 * 文本转语音
	 *
	 * @param request
	 * @param response
	 */
	@PostMapping("/text-to-audio")
	public void textToAudio(
		@RequestBody @Valid TextToAudioRequest request,
		HttpServletResponse response) {
		try {
			// 构建请求头
			HttpHeaders headers = new HttpHeaders();
			headers.setBearerAuth(apiKey);
			headers.setContentType(MediaType.APPLICATION_JSON);

			// 构建请求体 - 注意这里的变化
			Map<String, Object> requestBody = new HashMap<>();
			requestBody.put("user", AuthUtil.getUserId().toString());
			requestBody.put("message_id", request.getMessageId());


			HttpEntity<Map<String, Object>> requestEntity =
				new HttpEntity<>(requestBody, headers);

			// 设置响应头
			response.setContentType("audio/wav");
			response.setHeader("Content-Disposition", "attachment; filename=audio.wav");

			try {
				// 使用exchange方法替代execute
				ResponseEntity<byte[]> audioResponse = restTemplate.exchange(
					difyApiUrl + "/v1/text-to-audio",
					HttpMethod.POST,
					requestEntity,
					byte[].class
				);

				if (audioResponse.getBody() != null) {
					// 写入响应
					response.getOutputStream().write(audioResponse.getBody());
					response.getOutputStream().flush();
				} else {
					// 处理空响应
					response.setStatus(HttpServletResponse.SC_NO_CONTENT);
				}
			} catch (HttpClientErrorException | HttpServerErrorException e) {
				// 处理HTTP错误
				response.reset();
				response.setStatus(e.getRawStatusCode());
				response.setContentType("application/json;charset=UTF-8");

				Map<String, String> errorResponse = new HashMap<>();
				errorResponse.put("error", e.getStatusText());
				errorResponse.put("message", e.getResponseBodyAsString());

				response.getWriter().write(new ObjectMapper().writeValueAsString(errorResponse));
			}

		} catch (Exception e) {
			log.error("Error in text-to-audio conversion", e);
			try {
				// 处理其他错误
				response.reset();
				response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
				response.setContentType("application/json;charset=UTF-8");

				Map<String, String> errorResponse = new HashMap<>();
				errorResponse.put("error", "Internal Server Error");
				errorResponse.put("message", e.getMessage());

				response.getWriter().write(new ObjectMapper().writeValueAsString(errorResponse));
			} catch (IOException ex) {
				log.error("Error sending error response", ex);
			}
		}
	}


	/**
	 * 验证音频文件并返回正确的ContentType
	 */
	private ContentType getAudioContentType(MultipartFile file) {
		String fileName = file.getOriginalFilename();
		if (fileName == null) {
			throw new IllegalArgumentException("File name is required");
		}

		String extension = fileName.toLowerCase();

		// 根据文件扩展名判断类型
		if (extension.endsWith(".mp3")) {
			return ContentType.create("audio/mpeg");
		} else if (extension.endsWith(".mp4")) {
			return ContentType.create("audio/mp4");
		} else if (extension.endsWith(".wav")) {
			return ContentType.create("audio/wav");
		} else if (extension.endsWith(".m4a")) {
			return ContentType.create("audio/m4a");
		} else if (extension.endsWith(".webm")) {
			return ContentType.create("audio/webm");
		} else if (extension.endsWith(".mpga")) {
			return ContentType.create("audio/mpeg");
		} else {
			throw new IllegalArgumentException("Unsupported audio format. Supported formats are: " +
				"mp3, mp4, mpeg, mpga, m4a, wav, webm");
		}
	}

	/**
	 * 验证音频文件
	 */
	private void validateAudioFile(MultipartFile file) {
		if (file == null || file.isEmpty()) {
			throw new IllegalArgumentException("Audio file is required");
		}

		// 检查文件大小（15MB限制）
		long maxSize = 15 * 1024 * 1024L; // 15MB in bytes
		if (file.getSize() > maxSize) {
			throw new IllegalArgumentException("File size exceeds 15MB limit");
		}

		// 获取文件名
		String fileName = file.getOriginalFilename();
		if (fileName == null) {
			throw new IllegalArgumentException("File name is required");
		}

		// 检查文件扩展名
		String extension = fileName.toLowerCase();
		boolean isValid = extension.endsWith(".mp3") ||
			extension.endsWith(".mp4") ||
			extension.endsWith(".wav") ||
			extension.endsWith(".m4a") ||
			extension.endsWith(".webm") ||
			extension.endsWith(".mpga") ||
			extension.endsWith(".mpeg");

		if (!isValid) {
			throw new IllegalArgumentException("Unsupported audio format. Supported formats are: " +
				"mp3, mp4, mpeg, mpga, m4a, wav, webm");
		}
	}

}


